package com.irdstudio.efp.nls.service.impl.yed;

import com.irdstudio.basic.framework.core.exception.BizException;
import com.irdstudio.basic.framework.core.threadpool.ApplicationThreadPool2;
import com.irdstudio.basic.framework.core.util.DateUtility;
import com.irdstudio.basic.framework.core.util.StringUtil;
import com.irdstudio.basic.framework.core.util.TimeUtil;
import com.irdstudio.efp.console.common.YedConstantSet;
import com.irdstudio.efp.esb.service.bo.req.hlw.ReqAlarmJudgementBean;
import com.irdstudio.efp.esb.service.bo.req.yed.YedGjjAccInfoReqBean;
import com.irdstudio.efp.esb.service.bo.req.yed.YedGjjCompnayInfoRequestBean;
import com.irdstudio.efp.esb.service.bo.resp.hlw.RespAlarmJudgementBean;
import com.irdstudio.efp.esb.service.bo.resp.yed.YedGjjAccNoInfoResponseBean;
import com.irdstudio.efp.esb.service.bo.resp.yed.YedGjjCompanyInfoResponseBean;
import com.irdstudio.efp.esb.service.facade.hlw.AlarmJudgementService;
import com.irdstudio.efp.esb.service.facade.yed.YedCompanyInfoService;
import com.irdstudio.efp.limit.service.facade.LmtPrdContService;
import com.irdstudio.efp.limit.service.vo.LmtPrdContVO;
import com.irdstudio.efp.loan.service.facade.AccLoanService;
import com.irdstudio.efp.loan.service.facade.LoanRepayPlanService;
import com.irdstudio.efp.loan.service.vo.AccLoanVO;
import com.irdstudio.efp.loan.service.vo.LoanRepayPlanVO;
import com.irdstudio.efp.nls.common.constant.PrdAdaptedSoltEnums;
import com.irdstudio.efp.nls.common.util.SocketClientUtil;
import com.irdstudio.efp.nls.service.facade.NlsApplyInfoService;
import com.irdstudio.efp.nls.service.facade.YedGjjInvoteService;
import com.irdstudio.efp.nls.service.facade.bean.YedSxGjjInvoteReqBean;
import com.irdstudio.efp.nls.service.facade.bean.YedSxGjjLoanReaseReqBean;
import com.irdstudio.efp.nls.service.facade.sx.NlsCreditInfoService;
import com.irdstudio.efp.nls.service.facade.yed.YedGjjLoanService;
import com.irdstudio.efp.nls.service.vo.NlsApplyInfoVO;
import com.irdstudio.efp.nls.service.vo.YedGjjInvoteVO;
import com.irdstudio.efp.nls.service.vo.queue.NlsProcessBizVO;
import com.irdstudio.efp.nls.service.vo.sx.NlsCreditInfoVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCluster;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

@Service("yedGjjLoanService")
public class YedGjjLoanServiceImpl implements YedGjjLoanService {

    private final Logger logger = LoggerFactory.getLogger(YedGjjLoanServiceImpl.class);

    @Autowired
    @Qualifier("applicationThreadPool")
    private ApplicationThreadPool2 threadPool;

    @Autowired
    @Qualifier("lmtPrdContService")
    private LmtPrdContService lmtPrdContService;

    @Autowired
    @Qualifier("accLoanService")
    private AccLoanService accLoanService;
    @Autowired
    private NlsCreditInfoService nlsCreditInfoService;
    @Autowired
    private NlsApplyInfoService nlsApplyInfoService;
    @Autowired
    private YedGjjInvoteService yedGjjInvoteService;
    @Autowired
    private LoanRepayPlanService loanRepayPlanService;

    @Value("${send_to_gjj_ip}")
    private String ip;

    @Value("${send_to_gjj_port}")
    private String port;

    private static AtomicInteger msgCount = new AtomicInteger(1);


    @Override
    public void callSyncGjjInvoteApply(NlsApplyInfoVO nlsApplyInfoVO) {
//        nlsApplyInfoVO.setApplySeq("YX20190426121212000152-b");
//        nlsApplyInfoVO = nlsApplyInfoService.queryByPk(nlsApplyInfoVO);

        logger.info("调用公积金回写接口开始-用信阶段："+nlsApplyInfoVO.getApplySeq());
        LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
        lmtPrdContVO.setLmtApplySeq(nlsApplyInfoVO.getLmtApplySeq());
        lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);

        AccLoanVO accLoanVO = new AccLoanVO();
        accLoanVO.setApplySeq(nlsApplyInfoVO.getApplySeq());
        accLoanVO = accLoanService.queryByApplySeq(accLoanVO);

        String stdbwtype = "Request";//报文类型：Request/Response
        String stdprocode = "DS32";//交易码
        String stdyhdm = "21";//银行代码:广州银行21
        //交易流水号:交易码(4位)+银行代码(2位)+发送日期(yyyymmdd8位)+当日该接口的发送序号(6位);例如：DS10 21 20171011 000001
        String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String stdseqnum = seqGenerator(stdprocode + stdyhdm + currentDate,6);

        //报送公积金记录表
        YedGjjInvoteVO vo = new YedGjjInvoteVO();
        vo.setStdSeqnum(stdseqnum);
        vo.setSendDate(new Date());
        vo.setCertType(nlsApplyInfoVO.getCertType());
        vo.setCertCode(nlsApplyInfoVO.getCertCode());
        vo.setApplSeq(nlsApplyInfoVO.getApplySeq());
        vo.setApplType("2");
        vo.setCusName(nlsApplyInfoVO.getCusName());
        vo.setStdProcode(stdprocode);
        vo.setStdYhdm(stdyhdm);
        try{
            yedGjjInvoteService.insert(vo);
        }catch(Exception e){
            e.printStackTrace();
        }

        YedSxGjjLoanReaseReqBean reqBean = new YedSxGjjLoanReaseReqBean();

        if(Objects.isNull(lmtPrdContVO)){
            logger.error("优e贷用信流水号："+nlsApplyInfoVO.getApplySeq()+"的额度合同信息为空！");
            return;
        }
        if(Objects.isNull(accLoanVO)){
            logger.error("优e贷用信流水号："+nlsApplyInfoVO.getApplySeq()+"的借据信息为空！");
            return;
        }
        //查询还款计划表
        LoanRepayPlanVO loanRepayPlanVO = new LoanRepayPlanVO();
        loanRepayPlanVO.setRefNbr(accLoanVO.getBillNo());
        loanRepayPlanVO.setTerm(1);
        loanRepayPlanVO = loanRepayPlanService.getLoanRepayPlanByRefNbrAndTerm(loanRepayPlanVO);
        BigDecimal stdyhke = BigDecimal.ZERO;
        if (Objects.nonNull(loanRepayPlanVO)){
            stdyhke = loanRepayPlanVO.getPrincipal().add(loanRepayPlanVO.getInterest());
        }

        if(StringUtils.isBlank(nlsApplyInfoVO.getCertType())
                || StringUtils.isBlank(nlsApplyInfoVO.getCertCode())
                || StringUtils.isBlank(nlsApplyInfoVO.getCusName())
                || StringUtils.isBlank(lmtPrdContVO.getLmtContNo())
                || StringUtils.isBlank(accLoanVO.getContNo())
                || StringUtils.isBlank(accLoanVO.getBillNo())
                || Objects.isNull(accLoanVO.getLoanAmount())
                || StringUtils.isBlank(accLoanVO.getReturnDate())){
            logger.error("优e贷用信流水号："+nlsApplyInfoVO.getApplySeq()+"的必输项为空值！");
            return;
        }

        reqBean.setStdidtype("10100".equals(nlsApplyInfoVO.getCertType())?"01":"");//证件类型 01-居民身份证
        reqBean.setStdidno(nlsApplyInfoVO.getCertCode());//证件号码
        reqBean.setStdxm(nlsApplyInfoVO.getCusName());//姓名
        reqBean.setStdsxbh(Objects.nonNull(lmtPrdContVO)?lmtPrdContVO.getLmtContNo():"");//授信编号
        reqBean.setStdcontrnm(Objects.nonNull(accLoanVO)?accLoanVO.getContNo():"");//合同编号
        reqBean.setStdbrno(Objects.nonNull(accLoanVO)?accLoanVO.getBillNo():"");//贷款编号
        reqBean.setStdfkje(Objects.nonNull(accLoanVO)?accLoanVO.getLoanAmount(): BigDecimal.ZERO);//放款金额
        reqBean.setStdfksj(Objects.nonNull(accLoanVO)?accLoanVO.getFirstDisbDate().replace("-",""):"");//放款日期
        reqBean.setStddkqs(Objects.nonNull(accLoanVO)?accLoanVO.getLoanTerm().toString():"");//贷款期数
        reqBean.setStdydhkr(Objects.nonNull(accLoanVO)?accLoanVO.getReturnDate():"");//还款日
        reqBean.setStd400stcd("6".equals(nlsApplyInfoVO.getDnSts())?"000":"001");//处理状态  000-放款成功  001-终止放款

        String reqhead = "<?xml version=\"1.0\" encoding=\"GBK\"?>";
        String headStr = "<HEAD>"+
                "<stdbwtype>"+stdbwtype+"</stdbwtype>"+
                "<stdprocode>"+stdprocode+"</stdprocode>"+
                "<stdyhdm>"+stdyhdm+"</stdyhdm>"+
                "<stdseqnum>"+stdseqnum+"</stdseqnum>"+
                "</HEAD>";

        String bodyStr = "<ROOT>"+
                "<stdidtype>"+reqBean.getStdidtype()+"</stdidtype>"+
                "<stdidno>"+reqBean.getStdidno()+"</stdidno>"+
                "<stdxm>"+reqBean.getStdxm()+"</stdxm>"+
                "<stdsxbh>"+reqBean.getStdsxbh()+"</stdsxbh>"+
                "<stdcontrnm>"+reqBean.getStdcontrnm()+"</stdcontrnm>"+
                "<stdbrno>"+reqBean.getStdbrno()+"</stdbrno>"+
                "<stdfkje>"+reqBean.getStdfkje()+"</stdfkje>"+
                "<stdfksj>"+reqBean.getStdfksj()+"</stdfksj>"+
                "<stddkqs>"+reqBean.getStddkqs()+"</stddkqs>"+
                "<stdyhke>"+stdyhke+"</stdyhke>"+
                "<stdydhkr>"+reqBean.getStdydhkr()+"</stdydhkr>"+
                "<std400stcd>"+reqBean.getStd400stcd()+"</std400stcd>"+
                "</ROOT>";

        String reqStr1 =  reqhead + headStr + bodyStr;

        try{
            //发送公积金接口，验证客户身份信息
            YedGjjCompanyInfoResponseBean responseBean = getYedGjjAccNoInfoResponseBean(nlsApplyInfoVO.getCertType(),nlsApplyInfoVO.getCertCode(),
                    nlsApplyInfoVO.getCusName());
            if (Objects.nonNull(responseBean)){
                logger.info("nls-调用外数平台查询公积金账号成功");
                threadPool.add(() -> {
                    try {
                        sendGjj(reqStr1,nlsApplyInfoVO.getApplySeq());
                    } catch (Exception e) {
                        logger.error("用信阶段-调用公积金回写接口失败，流水号："+nlsApplyInfoVO.getApplySeq());
                    }

                });

            }

        }catch (Exception e){
            logger.error(e.getMessage());
        }
    }

    /**
     * 授信阶段回写公积金接口
     * @param nlsCreditInfoVO
     */
    @Override
    public void callSyncGjjInvoteCredit(NlsCreditInfoVO nlsCreditInfoVO){
//        nlsCreditInfoVO.setLmtApplySeq("SX20190426121212000275-b");
//        nlsCreditInfoVO = nlsCreditInfoService.queryByPk(nlsCreditInfoVO);
        logger.info("调用公积金回写接口开始-授信阶段："+nlsCreditInfoVO.getLmtApplySeq());

        LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
        lmtPrdContVO.setLmtApplySeq(nlsCreditInfoVO.getLmtApplySeq());
        lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);

        String stdbwtype = "Request";//报文类型：Request/Response
        String stdprocode = "DS31";//交易码
        String stdyhdm = "21";//银行代码:广州银行21
        //交易流水号:交易码(4位)+银行代码(2位)+发送日期(yyyymmdd8位)+当日该接口的发送序号(6位);例如：DS10 21 20171011 000001
        String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String stdseqnum = seqGenerator(stdprocode + stdyhdm + currentDate,6);

        //报送公积金记录表
        YedGjjInvoteVO vo = new YedGjjInvoteVO();
        vo.setStdSeqnum(stdseqnum);
        vo.setSendDate(new Date());
        vo.setCertType(nlsCreditInfoVO.getCertType());
        vo.setCertCode(nlsCreditInfoVO.getCertCode());
        vo.setApplSeq(nlsCreditInfoVO.getLmtApplySeq());
        vo.setApplType("1");
        vo.setCusName(nlsCreditInfoVO.getCusName());
        vo.setStdProcode(stdprocode);
        vo.setStdYhdm(stdyhdm);
        try{
            yedGjjInvoteService.insert(vo);
        }catch(Exception e){
            e.printStackTrace();
        }

        if(Objects.isNull(lmtPrdContVO)){
            logger.error("优e贷用信流水号："+nlsCreditInfoVO.getLmtApplySeq()+"的额度合同信息为空！");
            return;
        }

        if(StringUtils.isBlank(nlsCreditInfoVO.getCertType())
                || StringUtils.isBlank(nlsCreditInfoVO.getCertCode())
                || StringUtils.isBlank(nlsCreditInfoVO.getCusName())
                || StringUtils.isBlank(lmtPrdContVO.getLmtContNo())
                || Objects.isNull(nlsCreditInfoVO.getApproveAmt())){
            logger.error("优e贷用信流水号："+nlsCreditInfoVO.getLmtApplySeq()+"的必输项为空值！");
            return;
        }


        YedSxGjjInvoteReqBean reqBean = new YedSxGjjInvoteReqBean();
        reqBean.setStdidtype("10100".equals(nlsCreditInfoVO.getCertType())?"01":"");//证件类型 01-居民身份证
        reqBean.setStdidno(nlsCreditInfoVO.getCertCode());//证件号码
        reqBean.setStdxm(nlsCreditInfoVO.getCusName());//姓名
        reqBean.setStdsxbh(Objects.nonNull(lmtPrdContVO)?lmtPrdContVO.getLmtContNo():"");//授信编号
        reqBean.setStdsxje(nlsCreditInfoVO.getApproveAmt());//授信金额
        reqBean.setStd400stcd("02".equals(nlsCreditInfoVO.getApprvSts())?"000":"001");//处理状态  000审批通过

        //封装xml报文
        String reqhead = "<?xml version=\"1.0\" encoding=\"GBK\"?>";
        String headStr = "<HEAD>"+
                "<stdbwtype>"+stdbwtype+"</stdbwtype>"+
                "<stdprocode>"+stdprocode+"</stdprocode>"+
                "<stdyhdm>"+stdyhdm+"</stdyhdm>"+
                "<stdseqnum>"+stdseqnum+"</stdseqnum>"+
                "</HEAD>";

        String bodyStr = "<ROOT>"+
                "<stdidtype>"+reqBean.getStdidtype()+"</stdidtype>"+
                "<stdidno>"+reqBean.getStdidno()+"</stdidno>"+
                "<stdxm>"+reqBean.getStdxm()+"</stdxm>"+
                "<stdsxbh>"+reqBean.getStdsxbh()+"</stdsxbh>"+
                "<stdsxje>"+reqBean.getStdsxje()+"</stdsxje>"+
                "<std400stcd>"+reqBean.getStd400stcd()+"</std400stcd>"+
                "</ROOT>";

        String reqStr1 =  reqhead + headStr + bodyStr;

        try{
            threadPool.add(() -> {
                try {
                    sendGjj(reqStr1,nlsCreditInfoVO.getLmtApplySeq());
                } catch (Exception e) {
                    logger.error("授信阶段-调用公积金回写接口失败，流水号："+nlsCreditInfoVO.getLmtApplySeq());
                }
            });


        }catch (Exception e){
            logger.error(e.getMessage());
        }
    }

    /**
     * 更新报送公积金记录表的接收状态
     * @param requestString
     */
    public void updateYedGjjInvote(String requestString){
        if (requestString.contains("stdjsbz") && requestString.contains("stdseqnum") && requestString.contains("stdresdesc")){
            String stdjsbz = requestString.split("<stdjsbz>")[1].split("</stdjsbz>")[0];
            String stdseqnum = requestString.split("<stdseqnum>")[1].split("</stdseqnum>")[0];
            String stdresdesc = requestString.split("<stdresdesc>")[1].split("</stdresdesc>")[0];
            YedGjjInvoteVO vo2 = new YedGjjInvoteVO();
            vo2.setStdSeqnum(stdseqnum);
            vo2.setStdState(stdjsbz);//接收状态
            vo2.setStdResdesc(stdresdesc);//错误信息
            try{
                yedGjjInvoteService.updateByPk(vo2);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }


    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 自增序列号
     *
     * @param prefix    前缀
     * @param numLength 要生成多少位的数字
     * @return
     */
    public String seqGenerator(String prefix, int numLength) {
        String upperCode = "";
        Long size = redisTemplate.opsForList().size(prefix);//查找以prefix作为key值的数据长度
        if (size > 0) {//有数据
            List leve = redisTemplate.opsForList().range(prefix, 0, -1);//获取该key下面的所有值 （-1所有值；1下一个值）
            upperCode = leve.get(leve.size() - 1).toString();//返回最后一个值
        }
        String returnCode = "";
        int Suffix;//后缀数字
        if (!StringUtil.isEmpty(upperCode)) {//有数据
            String sequence = upperCode.substring(prefix.length());//截取前缀开始的后面数字
            Suffix = Integer.parseInt(sequence);
            Suffix++;//最后的序号加一
        } else {//没有数据
            Suffix = 1;
        }
        returnCode = prefix + String.format("%0" + numLength + "d", Suffix);//后缀不够numLength长，前面补充0
        redisTemplate.opsForList().rightPush(prefix, returnCode);//存入Redis
        return returnCode;
    }


    public static void main(String[] args) {

        String xml = "<?xml version=\"1.0\" encoding=\"GBK\"?><HEAD>\n" +
                "  <stdbwtype>Response</stdbwtype>\n" +
                "  <stdyhdm>21</stdyhdm>\n" +
                "  <stdprocode>DS31</stdprocode>\n" +
                "  <stdseqnum>DS312120200930000007</stdseqnum>\n" +
                "  <stdrescode>00</stdrescode>\n" +
                "  <stdresdesc>交易成功</stdresdesc>\n" +
                "</HEAD><ROOT>\n" +
                "  <stdjsbz>1</stdjsbz>\n" +
                "</ROOT>";
        try{
            String s = xml.split("<stdresdesc>")[1].split("</stdresdesc>")[0];
            System.out.println(s);

        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 发送公积金接口，验证客户身份信息
     * @param certType
     * @param certCode
     * @param name
     * @return
     * @throws Exception
     */
    private YedGjjCompanyInfoResponseBean getYedGjjAccNoInfoResponseBean(String certType, String certCode, String name) throws Exception {
        YedGjjCompnayInfoRequestBean gjjRequestBean = new YedGjjCompnayInfoRequestBean();
        gjjRequestBean.setIdentNo(certCode);
        if("10100".equalsIgnoreCase(certType)){
            gjjRequestBean.setIdentTp("01");
        }
        gjjRequestBean.setBeQryPrsnNm(name);
        YedGjjCompanyInfoResponseBean responseBean = null;
        try{
            responseBean = yedCompanyInfoService.queryGJJCompanyInfoForEDS(gjjRequestBean);

        }catch (Exception e){
            e.printStackTrace();

        }
        return responseBean;
    }

    /**
     * 调公积金发送接口方法
     * @param reqStr1
     * @param applySeq
     * @throws Exception
     */
    public void sendGjj(String reqStr1,String applySeq) throws Exception{
        try {
            byte[] backinfo = new SocketClientUtil().sendMessageGjj(reqStr1,ip,port);
            String requestString = new String(backinfo, "GBK");
            logger.info("=========>解密返回报文："+ requestString);

            if (requestString.contains("stdrescode")){
                String stdrescode = requestString.split("<stdrescode>")[1].split("</stdrescode>")[0];
                if ("03".equals(stdrescode) || "04".equals(stdrescode)){
                    throw new Exception("【调用公积金回写接口】申请流水号：" + applySeq + " 执行调用公积金回写接口连接超时了，进入重试方法");
                }
            }
            updateYedGjjInvote(requestString);
        } catch (Exception e) {
            logger.error("授信阶段-调用公积金回写接口失败，流水号："+applySeq);
            if(msgCount.intValue() > 3){
                logger.info("重试3次调用公积金回写接口仍失败，请联系外数系统！！！");
                msgCount.set(1);
                ReqAlarmJudgementBean reqAlarmJudgementBean = new ReqAlarmJudgementBean();
                reqAlarmJudgementBean.setAlrmInf("重试3次调用公积金回写接口仍失败，请联系外数系统！！！");
                /*try {
                    getrespAlarmJudgementBean(reqAlarmJudgementBean);
                } catch (Exception alarme) {
                    alarme.printStackTrace();
                    logger.debug("调用告警接口异常！" + alarme.getMessage());
                }*/
                throw new Exception("【调用公积金回写接口】申请流水号：" + applySeq + " 执行调用公积金回写接口出现异常，异常信息为：" + e.getMessage());
            }
            while(msgCount.intValue() <= 3){
                Thread.sleep(30000);
                logger.error("执行调用公积金回写接口出现异常，出错信息为："+e.getMessage());
                logger.info("开始重试第"+msgCount.intValue()+"次调用公积金回写接口！！！");
                msgCount.incrementAndGet();
                sendGjj(reqStr1,applySeq);
            }
        }
    }

    /**
     *
     * 调用颖风写的告警判断服务
     *
     * @param reqAlarmJudgementBean
     * @return
     * @throws Exception
     * @author liyakui
     * @since 2019年1月28日 上午8:36:25
     * @version 1.0
     */
    public RespAlarmJudgementBean getrespAlarmJudgementBean(ReqAlarmJudgementBean reqAlarmJudgementBean) throws Exception {
        RespAlarmJudgementBean respAlarmJudgementBean = null;
        try {
            // 调用颖风写的告警判断服务
            reqAlarmJudgementBean.setMonObjNm("优e贷");
            reqAlarmJudgementBean.setMonObjSpfTpVal("外部接口");
            reqAlarmJudgementBean.setMonObjLctr(InetAddress.getLocalHost().getHostAddress());// 获取本机IP
            reqAlarmJudgementBean.setAlrmTmstmp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((new Date())));
            reqAlarmJudgementBean.setMonAlrmLvl("3");
            respAlarmJudgementBean = alarmJudgementService.alarmJudgement(reqAlarmJudgementBean);
            logger.debug("调用告警判断返回码：【" + respAlarmJudgementBean.getRetCd() + "】，返回信息：【" + respAlarmJudgementBean.getRetMsg() + "】");
        } catch (Exception e) {
            logger.info("调用告警接口异常！" + e.getMessage());
            throw e;
        }
        return respAlarmJudgementBean;
    }

    @Autowired
    private YedCompanyInfoService yedCompanyInfoService;
    @Autowired
    private AlarmJudgementService alarmJudgementService;

}
